#include "llSystemInfo.hpp"
#include "llOption.hpp"
using namespace llmake;
#include <boost/tr1/memory.hpp>
using namespace std::tr1;
extern shared_ptr<llOption> global_Option;

#include <iostream>
#include<fstream>
#include <list>
using namespace std;
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
#include <boost/program_options.hpp>
#include <boost/program_options/environment_iterator.hpp>
#include <boost/algorithm/string.hpp>
namespace po = boost::program_options;


llSystemInfo::llSystemInfo()
 :m_PWD("")
 ,m_Home("")
 ,m_GCC(false)
 ,m_MSVC(false)
 ,m_MINGW(false)
 ,m_WIN32(false)
 ,m_Linux(false)
 ,m_CPUS(1)
 ,m_CMakeModulePath("")
{
//cout<<"__FILE__:("<<__FILE__<<") __LINE__:("<<__LINE__<<")"<<endl;
	path full_path;
	full_path = current_path();
	m_PWD=full_path.string();

//cout<<"__FILE__:("<<__FILE__<<") __LINE__:("<<__LINE__<<")"<<endl;
	char *home = getenv("LLMAKE_HOME");
	if ( NULL == home )
	{
		cout<<"LLMAKE_HOME have not been set ,please reinstall llmake"<<endl;
		exit(-1);
	}
//cout<<"__FILE__:("<<__FILE__<<") __LINE__:("<<__LINE__<<")"<<endl;
	m_Home = home;
//cout<<"__FILE__:("<<__FILE__<<") __LINE__:("<<__LINE__<<")"<<endl;
	try
	{
		po::options_description config("Compiler Configuration");
		config.add_options()
			("CC", po::value<string>(),"c source compiler")
			("CXX", po::value<string>(),"c++ source compiler")
			("BC_LINK", po::value<string>(),"byte code linker")
			("BC_AR", po::value<string>(),"byte code AR")
			("BC_LD_LIB", po::value<string>(),"byte code lib linker")
			("BC_LD_EXE", po::value<string>(),"byte code execute linker")
			("BC_OPT", po::value<string>(),"byte code optizationed")
			("BC_LLC", po::value<string>(),"byte code to asm")
			("NATIVE_AR", po::value<string>(),"native code ar")
			("NATIVE_AS", po::value<string>(),"native code as")
			("NATIVE_LD", po::value<string>(),"native code c ld")
			("NATIVE_CXX_LD", po::value<string>(),"native code c++ ld")
			("STRIP", po::value<string>(),"strip execute")
			("MKDIR", po::value<string>(),"make directory")
			("CP", po::value<string>(),"copy file")
			("MV", po::value<string>(),"move file")
			("GCC", po::value<bool>(),"c++ source compiler")
			("MSVC", po::value<bool>(),"c++ source compiler")
			("MINGW", po::value<bool>(),"c++ source compiler")
			("WIN32", po::value<bool>(),"c++ source compiler")
			("Linux", po::value<bool>(),"c++ source compiler")
			("CMAKE_MODULE_PATH", po::value<string>(),"cmake module path")
			("cflag_Release", po::value<string>(),"release cflags")
			("cflag_Debug", po::value<string>(),"debug cflags")
			("NULL", po::value<string>(),"compiler command end");
		po::options_description config_file_options;
		config_file_options.add(config);
        	po::variables_map vm;
		

		string confName;
		if ( global_Option->m_Clang )
		{
			confName=  m_Home + "/bin/clang_compile.conf";
		}
		else
		{
			confName=  m_Home + "/bin/compile.conf";
		}
        ifstream ifs(confName.c_str());
        store(parse_config_file(ifs, config_file_options), vm);
		
		confName=  m_Home + "/bin/SystemInfo.conf";
        ifstream ifs2(confName.c_str());
        store(parse_config_file(ifs2, config_file_options), vm);
        
		notify(vm);
		
		if (vm.count("CC"))
		{
			string command = vm["CC"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
//			cout<<command<<endl;
			m_SysComm["${CC}"] = command;
		}
		if (vm.count("CXX"))
		{
			string command = vm["CXX"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${CXX}"] = command;
		}
		if (vm.count("BC_LINK"))
		{
			string command = vm["BC_LINK"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_LINK}"] = command;
		}
		if (vm.count("BC_AR"))
		{
			string command = vm["BC_AR"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_AR}"] = command;
		}
		if (vm.count("BC_LD_LIB"))
		{
			string command = vm["BC_LD_LIB"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_LD_LIB}"] = command;
		}
		if (vm.count("BC_LD_EXE"))
		{
			string command = vm["BC_LD_EXE"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_LD_EXE}"] = command;
		}
		if (vm.count("BC_OPT"))
		{
			string command = vm["BC_OPT"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_OPT}"] = command;
		}
		if (vm.count("BC_LLC"))
		{
			string command = vm["BC_LLC"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${BC_LLC}"] = command;
		}
		if (vm.count("NATIVE_AS"))
		{
			string command = vm["NATIVE_AS"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${NATIVE_AS}"] = command;
		}
		if (vm.count("NATIVE_AR"))
		{
			string command = vm["NATIVE_AR"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${NATIVE_AR}"] = command;
		}
		if (vm.count("NATIVE_LD"))
		{
			string command = vm["NATIVE_LD"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${NATIVE_LD}"] = command;
		}
		if (vm.count("NATIVE_CXX_LD"))
		{
			string command = vm["NATIVE_CXX_LD"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${NATIVE_CXX_LD}"] = command;
		}
		if (vm.count("STRIP"))
		{
			string command = vm["STRIP"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${STRIP}"] = command;
		}
		if (vm.count("MKDIR"))
		{
			string command = vm["MKDIR"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${MKDIR}"] = command;
		}
		if (vm.count("CP"))
		{
			string command = vm["CP"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${CP}"] = command;
		}
		if (vm.count("MV"))
		{
			string command = vm["MV"].as<string>();
			boost::replace_first(command,"${LLMAKE_HOME}",m_Home);
			m_SysComm["${MV}"] = command;
		}

//
		if (vm.count("GCC"))
		{
			m_GCC = vm["GCC"].as<bool>();
			m_SysExpr["GCC"] = m_GCC;
//			cout<<m_GCC<<endl;
		}
		if (vm.count("MSVC"))
		{
			m_MSVC = vm["MSVC"].as<bool>();
			m_SysExpr["MSVC"] = m_MSVC;
//			cout<<m_MSVC<<endl;
		}
		if (vm.count("MINGW"))
		{
			m_MINGW = vm["MINGW"].as<bool>();
			m_SysExpr["MINGW"] = m_MINGW;
//			cout<<m_MINGW<<endl;
		}
		if (vm.count("WIN32"))
		{
			m_WIN32 = vm["WIN32"].as<bool>();
			m_SysExpr["WIN32"] = m_WIN32;
//			cout<<m_WIN32<<endl;
		}
		if (vm.count("Linux"))
		{
			m_Linux = vm["Linux"].as<bool>();
			m_SysExpr["Linux"] = m_Linux;
//			cout<<m_Linux<<endl;
		}
		if (vm.count("CMAKE_MODULE_PATH"))
		{
			m_CMakeModulePath = vm["CMAKE_MODULE_PATH"].as<string>();
			boost::replace_first(m_CMakeModulePath,"${LLMAKE_HOME}",m_Home);
		}
	}
	catch(exception& e)
	{
		cout<<"exception:" << e.what() << endl;
//        exit (-1);
	}
//cout<<"__FILE__:("<<__FILE__<<") __LINE__:("<<__LINE__<<")"<<endl;

	if(m_WIN32)
	{
		char *cpus = getenv("NUMBER_OF_PROCESSORS");
		if(cpus)
		{
			m_CPUS= atoi(cpus);
		}
	}
	if( 1 > m_CPUS)
	{
		m_CPUS= 1;
	}
}
string llSystemInfo::getFullPath(  const string &mypath )
{
	path full_path(mypath);
	string root = full_path.root_directory();
	if( false == root.empty())
	{
		return full_path.string();
	}
	path full_path2( m_PWD +"/"+ mypath );
	return full_path2.string();
}

string llSystemInfo::simplePath(const string &mypath)
{
	path full_path(mypath);
	path::iterator pathI = full_path.begin();
	list<string> nameList;
	while (pathI != full_path.end())
	{
//		cout<<*pathI<<endl;
		if ( ".." == *pathI )
		{
			nameList.pop_back();
		}
		else if ( "." == *pathI )
		{
			;
		}
		else
		{
			nameList.push_back(*pathI);
		}
		++pathI;
	}
	list<string>::iterator nameIr = nameList.begin();
	string pathName;
	for( ; nameList.end() != nameIr ; nameIr++)
	{
//		cout<<*nameIr<<endl;
		pathName += *nameIr;
		list<string>::iterator lastIr = nameIr;
		lastIr++;
		if ( "/" != *nameIr && nameList.begin() != nameIr && nameList.end() != lastIr)
		{
			pathName += "/";
		}
	}
	return pathName;
}
string llSystemInfo::getSystemCommand(const string &crossComm)
{
	llSystemCommands::iterator it= m_SysComm.find(crossComm);
	if( m_SysComm.end() != it )
	{
		return it->second;
	}
	else
	{
		return "echo";
	}
}

bool llSystemInfo::getSystemExpr(const string &expr)
{
#ifdef DEBUG
		cout<<"expr ["<<expr<<"]"<<endl;
 #endif

	llSystemExpr::iterator it= m_SysExpr.find(expr);
	if( m_SysExpr.end() != it )
	{
#ifdef DEBUG
		cout<<"expr it->second "<<it->second<<endl;
#endif
		return it->second;
	}
	else
	{
#ifdef DEBUG
		cout<<"expr not found  "<<endl;
#endif
		return false;
	}
}
